﻿using System;
using System.Collections.Generic;
using GACore;
using GACore.Structures;

namespace PflanzenZAOptimierung
{
	class VectorRulesConverter
	{
		private string[] conditions;
		List<Cause> causesList = new List<Cause>();

		private FitnessProperties fitnessProperties;
		private CrossoverProperties crossoverProperties;

		public VectorRulesConverter(string[] rules, FitnessProperties fitnessProperties, CrossoverProperties crossoverProperties)
		{
			List<string> rulesWithoutComments = new List<string>();
			foreach (var rule in rules)
			{
				if (rule != "" && !rule.StartsWith("#"))
				{
					rulesWithoutComments.Add(rule);
				}
			}
			rules = rulesWithoutComments.ToArray();
			conditions = new string[rules.Length];
			this.fitnessProperties = fitnessProperties;
			this.crossoverProperties = crossoverProperties;
			SplitRules(rules);
		}

		private void SplitRules(string[] rules)
		{
			for (int i = 0; i < rules.Length; i++)
			{
				string[] rule = rules[i].Split(new string[] { "=>" }, StringSplitOptions.RemoveEmptyEntries);
				conditions[i] = rule[0];
				causesList.Add(new Cause(rule[1]));
			}
		}

		internal string[] VectorToRules(ref Vector<double> vector)
		{
			Normalize(ref vector);
			string[] retRules = new string[conditions.Length];
			for (int i = 0; i < conditions.Length; i++)
			{
				retRules[i] = conditions[i] + "=>" +
					causesList[i].ToString(vector[4 * i], vector[4 * i + 1], vector[4 * i + 2], vector[4 * i + 3]);
			}
			return retRules;
		}

		private void Normalize(ref Vector<double> vector)
		{
			int cellDefinitionCount = 4;
			for (int i = 0; i < vector.Length / cellDefinitionCount; i++)
			{
				double sum = 0;
				for (int j = 0; j < cellDefinitionCount; j++)
				{
					sum += vector[i * cellDefinitionCount + j];
					if (vector[i * cellDefinitionCount + j] < 0 || vector[i * cellDefinitionCount + j] > 1)
					{
						return;
					}
				}

				double toNorm = 1 / sum;

				for (int j = 0; j < cellDefinitionCount; j++)
				{
					vector[i * cellDefinitionCount + j] *= toNorm;
				}
			}
		}

		internal Vector<double> RulesToVector(string[] rules)
		{
			SplitRules(rules);
			Vector<double> vector = new Vector<double>(rules.Length * 4, fitnessProperties, crossoverProperties);
			for (int i = 0; i < causesList.Count; i++)
			{
				vector[4 * i] = causesList[i].Probabilities["Buche"];
				vector[4 * i + 1] = causesList[i].Probabilities["Birke"];
				vector[4 * i + 2] = causesList[i].Probabilities["Gräser"];
				vector[4 * i + 3] = causesList[i].Probabilities["Leer"];
			}
			return vector;
		}

		internal Vector<double> CreateRandomVector(Random random)
		{
			int cellDefinitionCount = Model.Environment.CellDefinitions.Count;
			Vector<double> retVector = new Vector<double>(conditions.Length * 4, fitnessProperties, crossoverProperties);
			for (int i = 0; i < conditions.Length; i++)
			{
				for (int j = 0; j < cellDefinitionCount; j++)
				{
					retVector[i * cellDefinitionCount + j] = random.NextDouble();
				}
			}
			Normalize(ref retVector);
			return retVector;
		}
	}
}
